package com.zimin.cloud.mine.web.aspect;

import com.alibaba.fastjson.JSON;
import com.zimin.cloud.mine.pojo.system.business.OperationLogBO;
import com.zimin.cloud.system.api.IOperationLogFeign;
import com.zimin.common.constant.ServletConstant;
import com.zimin.common.enums.Number;
import com.zimin.common.utils.AopUtils;
import com.zimin.common.utils.ServletUtil;
import com.zimin.shared.annotation.OpLog;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

/**
 * <p>  controller公共的切面获取接口日志</p>
 *
 * @author zimin
 * @since 2021/10/15 3:08 下午
 */
@Slf4j
@Aspect
@Component
public class OpLogAspect {

    @Autowired
    private IOperationLogFeign operationLogFeign;

    /**
     * <p>声明一个保存日志的切点</p>
     *
     * @return void
     * @since 2021-10-15 15:30:42
     */
    @Pointcut("execution(* com.zimin.cloud.*.controller.*.*(..))")
    public void logPointCut() {
    }

    @Around(value = "logPointCut()")
    public Object saveLogService(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("========开始执行{}.{}========", joinPoint.getTarget().getClass(), joinPoint.getSignature().getName());
        var start = System.currentTimeMillis();
        var result = joinPoint.proceed();
        var end = System.currentTimeMillis();
        var runTime = end - start;
        log.info("========执行{}.{}结束,共耗时{}毫秒========", joinPoint.getTarget().getClass(), joinPoint.getSignature().getName(), runTime);
        var opLog = AopUtils.getAnnotation(joinPoint, OpLog.class);
        if (ObjectUtils.isEmpty(opLog)) {
            return result;
        }
        try {
            var request = ServletUtil.getRequest();
            var mouldName = opLog.module().name();
            var action = opLog.action();
            var loginUserName = ServletUtil.getUserName();
            var accountId = ServletUtil.getUserId();
            var params = opLog.saveParams() ? JSON.toJSONString(joinPoint.getArgs()) : "";
            if (ObjectUtils.isEmpty(request)) {
                return result;
            }
            var url = request.getRequestURL().toString();
            var method = request.getMethod();
            var ip = ServletUtil.getIp();
            log.info("========保存{}.{}日志========", joinPoint.getTarget().getClass(), joinPoint.getSignature().getName());
            var operationLog = OperationLogBO.builder()
                    .businessType(getBusinessType(method))
                    .title(action)
                    .method(joinPoint.getSignature().getName())
                    .requestMethod(method)
                    .operatorUrl(url)
                    .operatorIp(ip)
                    .operatorType(1)
                    .runTime(runTime)
                    .operatorParam(params)
                    .operatorName(loginUserName)
                    .account(loginUserName)
                    .build();
            operationLogFeign.saveOperationLog(operationLog);
            log.info("accountId:{},moudleName:{},action:{},loginUserName:{},params:{},url:{},method:{},ipAddr:{}",
                    accountId, mouldName, action, loginUserName, params, url, method, ip);
        } catch (Exception e) {
            log.info("保存日志失败");
            e.printStackTrace();
        }
        return result;
    }

    /**
     * <p>获取业务类型</p>
     *
     * @param method
     * @return java.lang.Integer
     * @since 2022-04-11 11:25:54
     */
    private Integer getBusinessType(String method) {
        switch (method) {
            case ServletConstant.GET:
                return Number.ONE.getIntNum();
            case ServletConstant.POST:
                return Number.TWO.getIntNum();
            case ServletConstant.PUT:
                return Number.THREE.getIntNum();
            case ServletConstant.DELETE:
                return Number.FOUR.getIntNum();
            default:
                return Number.ZERO.getIntNum();

        }
    }


}
